#include "include.h"
#include "api_alg.h"
#include "dnn_L1.h"

#if DNN_L1_EN
static dnn_cb_t dnn_cb AT(.buf.dnn_L1);
static dnn_L1_mic_cfg_t dnn_L1_mic_cfg AT(.buf.dnn_L1);

typedef struct {
    u8 iptr;
    u8 optr;

} dnn_rdft_t;
dnn_rdft_t dnn_rdft AT(.buf.dnn_L1.fft);

s16 dnn_input[256] AT(.buf.dnn_L1.fft);
s16 dnn_output[256] AT(.buf.dnn_L1.fft);
s16 dnn_fft_in[512] AT(.buf.dnn_L1.fft);
s32 dnn_fft_out[512] AT(.buf.dnn_L1.fft);
s16 dnn_ifft_out[512] AT(.buf.dnn_L1.fft);
s16 dnn_fft_in_pre[512] AT(.buf.dnn_L1.fft);
s16 dnn_ifft_out_next[512] AT(.buf.dnn_L1.fft);
s16 dnn_cir[256] AT(.buf.dnn_L1.fft);
static fft_cfg_t fft_t;
static ifft_cfg_t ifft_t;

AT(.text.dnn_L1_proc)WEAK
void dnn_L1_mic_audio_input(u8 *ptr, u32 samples, int ch_mode, void *params)
{
    if(!dnn_L1_mic_cfg.mute){
        memcpy(&dnn_input[dnn_rdft.iptr * 120], ptr, 120 * 2);
        dnn_rdft.iptr++;
        if (dnn_rdft.iptr >= 2) {
            dnn_rdft.iptr = 0;
            memcpy(dnn_output, dnn_ifft_out_next, 240 * 2);
            memcpy(&dnn_fft_in_pre[240], dnn_input, 240 * 2);
            dnn_L1_mic_proc_kick_start();
            dnn_rdft.optr = 0;
        }
        memcpy(ptr, &dnn_output[dnn_rdft.optr * 120], 120 * 2);

        dnn_rdft.optr++;
        if (dnn_rdft.optr >= 2) {
            dnn_rdft.optr = 0;
        }

    }
    if (dnn_L1_mic_cfg.callback) {
        dnn_L1_mic_cfg.callback((void *)ptr, samples, ch_mode, params);
    }

}

//dnn_L1算法启动计算 放在低优先级现场处理
AT(.text.dnn_L1_proc)WEAK
void dnn_L1_mic_proc_cb(void)
{
    fft_cfg_t   *fft   = &fft_t;
    ifft_cfg_t  *ifft  = &ifft_t;
//    GPIOBSET |= BIT(2);

    fft_pre_window(dnn_fft_in_pre,dnn_fft_in);

    fft_hw(fft);

    dnn_L1_fre_process(dnn_fft_out);

    ifft_hw(ifft);

    fft_next_window(dnn_ifft_out_next,dnn_ifft_out,dnn_cir);
//    GPIOBCLR |= BIT(2);
    memcpy(&dnn_fft_in_pre[0], &dnn_fft_in_pre[240], 240 * 2);
}




AT(.text.dnn_L1_set)WEAK
void dnn_L1_mic_output_callback_set(audio_callback_t callback)
{
    dnn_L1_mic_cfg.callback = callback;
}

AT(.text.dnn_L1_init)WEAK
void dnn_L1_mic_init(u8 sample_rate, u16 samples)
{
    memset((uint8_t *)&dnn_cb, 0, sizeof(dnn_cb));
    memset((uint8_t *)&dnn_L1_mic_cfg, 0, sizeof(dnn_L1_mic_cfg));

    memset(dnn_input, 0, sizeof(dnn_input));
    memset(dnn_output, 0, sizeof(dnn_output));
    memset(dnn_fft_in, 0, sizeof(dnn_fft_in));
    memset(dnn_fft_out, 0, sizeof(dnn_fft_out));
    memset(dnn_ifft_out, 0, sizeof(dnn_ifft_out));
    memset(dnn_fft_in_pre, 0, sizeof(dnn_fft_in_pre));
    memset(dnn_ifft_out_next, 0, sizeof(dnn_ifft_out_next));
    memset(dnn_cir, 0, sizeof(dnn_cir));


	dnn_cb.param_printf           = 0;
	dnn_cb.nt                     = DNN_L1_LEVEL;
	dnn_cb.nt_post                = 0; //0-6 >0才起效 0为不开gain指数化 开的话默认为3
	dnn_cb.exp_range_H			   = 1;
	dnn_cb.exp_range_L			   = 0;
	dnn_cb.noise_ps_rate          = 1;
	dnn_cb.prior_opt_idx	       = 10;
	dnn_cb.prior_opt_ada_en	   = 0;
	dnn_cb.wind_level			   = 0;
	dnn_cb.wind_range			   = 0;
	dnn_cb.low_fre_range          = 1; //
	dnn_cb.low_fre_range0         = 1;
	//dnn_cb.pitch_filter_en		   = 1;
	dnn_cb.mask_floor			   = 1600;
	dnn_cb.mask_floor_r		   = 0;
	dnn_cb.music_lev			   = 36;
	dnn_cb.comforN_level		   = 1;
	dnn_cb.gain_expand			   = 1024;
	dnn_cb.nn_only				   = 1;
	dnn_cb.nn_only_len			   = 3;
	//dnn_cb.noise_db2			   = -15;
	dnn_cb.smooth_en			   = 1;
	dnn_cb.gain_assign			   = 16666;



    memset(&dnn_rdft, 0, sizeof(dnn_rdft_t));
    memset(&dnn_fft_in, 0, sizeof(dnn_fft_in));
    memset(&dnn_fft_out, 0, sizeof(dnn_fft_out));
    memset(&dnn_ifft_out, 0, sizeof(dnn_ifft_out));

    fft_cfg_t   *fft   = &fft_t;
    ifft_cfg_t  *ifft  = &ifft_t;

    fft->size           = RDFT_512;
	fft->input_type     = 0;
    fft->window_en      = 0;
    fft->isr_en         = 0;
    fft->in_addr        = dnn_fft_in;
    fft->out_addr       = dnn_fft_out;

    ifft->size          = RDFT_512;
    ifft->output_type   = 0;
    ifft->window_en     = 0;
    ifft->isr_en        = 0;
    ifft->overlap_en    = 0;
    ifft->in_addr       = dnn_fft_out;
    ifft->out_addr      = dnn_ifft_out;


    CLKGAT2 |= BIT(20);
    CLKGAT2 |= BIT(21);

    dnn_L1_init(&dnn_cb);

}

AT(.text.dnn_L1_exit)WEAK
void dnn_L1_mic_exit(void)
{

}

AT(.text.dnn_L1_set.param)WEAK
void dnn_L1_mic_param_set(int8_t dnn_L1_nt)
{

    memset((uint8_t *)&dnn_cb, 0, sizeof(dnn_cb));
    memset((uint8_t *)&dnn_L1_mic_cfg, 0, sizeof(dnn_L1_mic_cfg));

    memset(dnn_input, 0, sizeof(dnn_input));
    memset(dnn_output, 0, sizeof(dnn_output));
    memset(dnn_fft_in, 0, sizeof(dnn_fft_in));
    memset(dnn_fft_out, 0, sizeof(dnn_fft_out));
    memset(dnn_ifft_out, 0, sizeof(dnn_ifft_out));
    memset(dnn_fft_in_pre, 0, sizeof(dnn_fft_in_pre));
    memset(dnn_ifft_out_next, 0, sizeof(dnn_ifft_out_next));
    memset(dnn_cir, 0, sizeof(dnn_cir));

	dnn_cb.param_printf           = 0;
	dnn_cb.nt                     = dnn_L1_nt;
	dnn_cb.nt_post                = 0; //0-6 >0才起效 0为不开gain指数化 开的话默认为3
	dnn_cb.exp_range_H			   = 1;
	dnn_cb.exp_range_L			   = 0;
	dnn_cb.noise_ps_rate          = 1;
	dnn_cb.prior_opt_idx	       = 10;
	dnn_cb.prior_opt_ada_en	   = 0;
	dnn_cb.wind_level			   = 0;
	dnn_cb.wind_range			   = 0;
	dnn_cb.low_fre_range          = 1; //
	dnn_cb.low_fre_range0         = 1;
	//dnn_cb.pitch_filter_en		   = 1;
	dnn_cb.mask_floor			   = 1600;
	dnn_cb.mask_floor_r		   = 0;
	dnn_cb.music_lev			   = 36;
	dnn_cb.comforN_level		   = 1;
	dnn_cb.gain_expand			   = 1024;
	dnn_cb.nn_only				   = 1;
	dnn_cb.nn_only_len			   = 3;
	//dnn_cb.noise_db2			   = -15;
	dnn_cb.smooth_en			   = 1;
	dnn_cb.gain_assign			   = 16666;


    memset(&dnn_rdft, 0, sizeof(dnn_rdft_t));
    fft_cfg_t   *fft   = &fft_t;
    ifft_cfg_t  *ifft  = &ifft_t;

    fft->size           = RDFT_512;
	fft->input_type     = 0;
    fft->window_en      = 1;
    fft->isr_en         = 0;
    fft->in_addr        = dnn_fft_in;
    fft->out_addr       = dnn_fft_out;

    ifft->size          = RDFT_512;
    ifft->output_type   = 0;
    ifft->window_en     = 1;
    ifft->isr_en        = 0;
    ifft->overlap_en    = 1;
    ifft->in_addr       = dnn_fft_out;
    ifft->out_addr      = dnn_ifft_out;

    CLKGAT2 |= BIT(20);
    CLKGAT2 |= BIT(21);
    dnn_L1_init(&dnn_cb);
}

AT(.text.dnn_L1_set.mute)WEAK
void dnn_L1_mic_mute_set(uint8_t mute)
{
    dnn_L1_mic_cfg.mute = mute;
}

AT(.text.dnn_L1_get.mute)WEAK
uint8_t dnn_L1_mic_mute_get(void)
{
    return dnn_L1_mic_cfg.mute;
}

#endif
